package csrpg;

import java.io.*;
import java.util.*;
import org.twgg.cssula.ConsoleTool;

class Map{
    
    public Square[][] ground;
    public int rows, cols;
    public Hashtable<String, Role> roles = new Hashtable<String, Role>();
    private ConsoleTool ct = Game.ct;

    public Map(String fileName) {
        loadMap(fileName);
    }

    public void add(Role role) {
        roles.put(String.valueOf(role.name), role);
        ground[role.y][role.x].regestedRole = role;
        role.start();
    }

    public void add(Role role, int x, int y) {
        roles.put(String.valueOf(role.name), role);
        ground[y][x].regestedRole = role;
        role.x = x;
        role.y = y;
        role.start();
    }

    public void delete(Role role){
        role.stopThread();
        ground[role.y][role.x].regestedRole = null;
        roles.remove(String.valueOf(role.name));
    }

    public void delete(String key){
        Role r = roles.get(key);
        r.stopThread();
        ground[r.y][r.x].regestedRole = null;
        roles.remove(key);
    }

    public void loadMap(String fileName) {
        synchronized (Game.lock) {
            roles.clear();
            BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(fileName)));
            ArrayList<Square[]> al = new ArrayList<Square[]>();
            int largestWidth = 0;
            try {
                Square[] tmp = null;
                for (String s; (s = br.readLine()) != null;) {
                    char[] ca = s.toCharArray();
                    tmp = new Square[ca.length];
                    for (int i = 0; i < ca.length; i++) tmp[i] = new Square(ca[i]);
                    if (tmp.length > largestWidth) largestWidth = tmp.length;
                    al.add(tmp);
                }
                
                ground = new Square[al.size()][largestWidth];
                for (int i = 0; i < al.size(); i++) ground[i] = al.get(i);
                rows = ground.length;
                cols = ground[0].length;
                br.close();
            } catch (Exception e) {
                ConsoleTool.cls();
                e.printStackTrace();
            }
        }
    }
}
class Screen extends Thread {

    private Map map;
    private int x = 0, y = 0;
    private int rows, cols, leftEdge, upEdge, rightEdge, downEdge;
    private Square[][] buffer;
    private ConsoleTool ct = Game.ct;
    private Role focusRole = null;
    private boolean stop;

    public Screen(Map map, int rows, int cols) {
        setScreen(map, rows, cols);
    }

    public Screen(Map map) {
        setScreen(map, 21, 21);
    }

    public void setScreen(Map map, int rows, int cols){
        this.map = map;
        this.rows = rows;
        this.cols = cols;
        leftEdge = cols / 2-1;
        rightEdge = map.cols - 3 - (cols / 2 - 1);
        upEdge = rows / 2-1;
        downEdge = map.rows - 3 - (rows / 2 - 1);
        buffer = new Square[rows][cols];
        for (int i = 0; i < cols; i++)
            for (int j = 0; j < rows; j++)
                buffer[i][j] = new Square('　');
    }

    public void focus(Role role) {
        focusRole = role;
    }

    public void printScreen(int consoleX, int consoleY) {
        synchronized (Game.lock) {
            if (focusRole != null) {
                if (focusRole.x <= leftEdge)x = 1;
                else if (focusRole.x >= rightEdge) x = map.cols - cols-1;
                else x = focusRole.x - leftEdge;
                
                if (focusRole.y <= upEdge) y = 1;
                else if (focusRole.y >= downEdge) y = map.rows - rows-1;
                else y = focusRole.y - upEdge;
            }

            Square tmpSquare;
            for (int i = 0; i < cols; i++) {
                for (int j = 0; j < rows; j++) {
                    tmpSquare = map.ground[y + i][x + j];
                    if (!tmpSquare.equals(buffer[i][j])) {
                        ct.gotoXY(consoleX + j, consoleY + i);
                        if(tmpSquare.regestedRole!=null){
                            ct.setColor(tmpSquare.regestedRole.color);
                            System.out.print(tmpSquare.regestedRole.name);
                        }else{
                            ct.setColor(tmpSquare.color);
                            System.out.print(tmpSquare.name);
                        }
                        buffer[i][j].setSquare(tmpSquare.name, tmpSquare.color, tmpSquare.isBlock, tmpSquare.regestedRole);
                    }
                }
            }
        }
    }

    public void startThread() {
        stop = false;
        start();
    }

    public void stopThread() {
        stop = true;
    }

    @Override
    public void run() {
        try {
            while (!stop) {
                Thread.sleep(1);
                printScreen(1, 1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Square {

    public char name;
    public int color;
    public boolean isBlock;
    public Role regestedRole;

    public Square(char c) {
        name = c;
        setSquare(name);
    }

    public Square(char c, int color, boolean isBlock, Role role) {
        setSquare(c, color, isBlock, role);
    }

    public void setSquare(char c, int color, boolean isBlock, Role role) {
        name = c;
        this.color = color;
        this.isBlock = isBlock;
        regestedRole = role;
    }

    public void setSquare(char c) {
        switch (c) {
            case '█':
                color = ConsoleTool.RED;
                isBlock = true;
                break;
            case '※':
                color = ConsoleTool.GREEN;
                isBlock = false;
                break;
            default:
                color = ConsoleTool.WHITE;
                isBlock = false;
                break;
        }
        regestedRole = null;
    }

    @Override
    public boolean equals(Object obj) {
        boolean ans = false;
        if (obj instanceof Square) {
            Square square = (Square) obj;
            if (name == square.name && isBlock == square.isBlock && color == square.color && regestedRole == square.regestedRole) {
                ans = true;
            }
        }
        return ans;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 47 * hash + this.name;
        hash = 47 * hash + this.color;
        hash = 47 * hash + (this.isBlock ? 1 : 0);
        return hash;
    }
}